package com.eric.utils.page;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import com.eric.Config;
import com.eric.utils.Reader;
import com.eric.utils.TextUtils;

/**
 * 正文提取器，不同于Jsoup.document.text()方法，只提取大块的正文，导航等列表文字不提取<br>
 * <br>
 * 步骤： 1.提取包含最多文本的Element <br>
 * 2.如果其没有Siblings，则向上取Parent Node <br>
 * 3.提取对应的Sibling Elements <br>
 * 4.提取纯文本<br>
 */
public class ArticleExtractor {

	private Document doc;
	private String title;
	private Elements elements;
	private Element LARGEST_TXT_BLOCK;
	private String article;

	private boolean noImg = true;

	public static void main(String[] args) throws Exception {
		ArticleExtractor ex = new ArticleExtractor("https://baike.baidu.com/item/ABT/3503138");

		ex.extractImg();
		// System.out.println(ex.title);
		System.out.println(ex.extract());

	}

	/**
	 * 
	 * @param input
	 *            URL,Document(Jsoup),Text,File
	 */
	public ArticleExtractor(Object input) {
		doc = Reader.read2doc(input);
	}

	public ArticleExtractor noLineSep() {
		return this;
	}

	public ArticleExtractor extractImg() {
		noImg = false;
		return this;
	}

	public ArticleExtractor removeStopWords() {
		return this;
	}

	public String extract() {

		Map<String, Float> map = IR.getNodeTextRatio(doc);
		String[] select;
		try {
			select = getLargestTextNodeClass(map).split(" ");
			title = doc.title();
			elements = doc.select(select[0]);
			article = TextUtils.simplifyText(text(elements)).replaceAll("\n\n+", "");
		} catch (NullPointerException e) {

		}

		if (article == null)
			article = "";

		return article;// 删除多余空行
	}

	/**
	 * @deprecated
	 * @param classNames
	 * @param elements
	 * @return
	 */
	@SuppressWarnings("unused")
	private static String getClassNameOfArticle(Set<String> classNames, Elements elements) {
		String classNameOfLargestText = getClassNameOfLargestText(elements, classNames);
		Elements elementsThis;
		while (true) {
			classNames.remove(classNameOfLargestText);
			elementsThis = elements.select("." + classNameOfLargestText);
			classNameOfLargestText = getClassNameOfLargestText(elementsThis, classNames);
			if (!elements.select("." + classNameOfLargestText).select("h1").hasText())
				break;// 如果所选的class
			// name
			// 不包含h1，则退出循环
		}
		return classNameOfLargestText;
	}

	/**
	 * 根据node数量与text长度之间的比值进行排序，最大（即text长度相对node数量比值）的，作为文章所在的element
	 * 
	 * @param map
	 * @return
	 */
	public String getLargestTextNodeClass(Map<String, Float> map) {
		Entry<String, Float> returnEntry = null;
		for (Entry<String, Float> entry : map.entrySet()) {
			String curKey = entry.getKey().replaceAll("\\..*", "");

			if (!curKey.equals("p") && !curKey.equals("a") && !curKey.equals("strong") && !curKey.equals("span")) {

				if (returnEntry == null) {
					returnEntry = entry;

				} else if (returnEntry.getValue() < entry.getValue()) {
					returnEntry = entry;
				}
			}
		}

		return returnEntry.getKey();
	}

	/**
	 * @deprecated
	 * @param elements
	 * @param classNames
	 * @return
	 */
	private static String getClassNameOfLargestText(Elements elements, Set<String> classNames) {
		String className = null;
		String text = null;
		for (String s : classNames) {
			String selectText;
			String select = "." + s.replaceAll(" ", "");

			try {
				if (elements.select(select).hasText()) {
					selectText = elements.select(select).text();
					if (StringUtils.isBlank(text)) {
						text = selectText;
						className = s;
					} else if (selectText.length() > text.length()) {
						text = selectText;
						className = s;
					}
				}
			} catch (java.lang.IllegalArgumentException e) {
				e.printStackTrace();
			}

		}
		return className.replaceAll(" ", "");
	}

	/**
	 * 找到最大块文本所在的element
	 * 
	 * @deprecated
	 * @param elements
	 * @return Element
	 */
	public Element getLargestTextBlock() {
		Element curElement = null;
		for (Element element : elements) {
			if (curElement == null) {
				curElement = element;
			} else {
				curElement = (element.ownText().trim().length() > curElement.ownText().trim().length()
						&& !element.tagName().equals("title")) ? element : curElement;
			}
		}

		return curElement;
	}

	/**
	 * 找到最大块文本的sibling elements<br>
	 * 以及与最大文本块的class相近的elements
	 * 
	 * @deprecated
	 * @param largestTextBlock
	 * @return Elements
	 */
	@SuppressWarnings("unused")
	private Elements getSiblingTextBlocks() {
		Elements siblingElements = new Elements();
		Element e1 = LARGEST_TXT_BLOCK;

		while (e1.attr("class") == null || StringUtils.isBlank(e1.attr("class"))) {// 如果没有属性，则向上爬
			e1 = e1.parent();
		}
		Elements elements2 = doc.select(e1.tagName() + "." + e1.attr("class").trim().replaceAll("  *", "."));

		for (int i = 0; i < elements2.size(); i++) {
			if (!siblingElements.contains(elements2.get(i))) {
				siblingElements.add(elements2.get(i));
			}
		}
		return siblingElements;
	}

	/**
	 * 提取纯文本 图片链接以文本形式展示
	 * 
	 * @param textBlocks
	 * @return
	 */
	public String text(Elements textBlocks) {
		URL url = null;
		try {
			url = new URL(doc.baseUri());
		} catch (MalformedURLException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

		StringBuilder sb = new StringBuilder();
		Set<String> set = new HashSet<>();
		for (Element element : textBlocks) {
			element = TextUtils.removeStyle(element);
			element = TextUtils.removeLinks(element);
			for (Element e : element.getAllElements()) {
				if (noImg) {
				} else if (url != null) { // In case input is pure text
					if (e.tagName().equals("img")) {
						String imgSrc = null;
						try {
							imgSrc = IR.getImgSrc(e, url);
							if (set.contains(imgSrc)) {// 图片去重
							} else {
								set.add(imgSrc);
								sb.append(imgSrc);
								sb.append(System.lineSeparator());
							}
						} catch (NullPointerException exc) {
							System.out.println("No img src: " + e);
						}

					}
				}

				String text = e.ownText().trim();
				if (accepted(text) && !set.contains(text)) {
					set.add(text);
					sb.append(text);
					sb.append(System.lineSeparator());
				} else if (e.tagName().equals("p")) {
					sb.append(System.lineSeparator());
				}
			}
		}
		return sb.toString();
	}

	public boolean accepted(String text) {
		boolean accepted = true;
		if (text == null || StringUtils.isBlank(text) || TextUtils.chineseOnly(text).length() < 2) {// NULL，空，纯数字和英文
			accepted = false;
		}

		if (TextUtils.chineseOnly(text).length() <= Config.Min_PARAGRAPH_WORDS) {
			for (int i = 0; i < Config.COMMON_ACTIONS.length; i++) {
				if (text.contains(Config.COMMON_ACTIONS[i])) {
					accepted = false;
					break;
				}
			}
			for (int i = 0; i < Config.NONESENSE.length; i++) {
				if (text.contains(Config.NONESENSE[i])) {
					accepted = false;
					break;
				}
			}
		}

		return accepted;
	}

}
